package view;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import modelInterfaces.ITest;
import pluginInterfaces.IMetric;
import pluginInterfaces.IPluginClassificationMetric;
import pluginInterfaces.IPluginErrorMetric;
import pluginInterfaces.IRecommender;
import utils.Codes;
import utils.Messages;
import viewInterfaces.IViewTestSetup;
import controllerInterfaces.IControllerTestSetup;

/**
 * View used to select the algorithms and metrics that will be included in a test this is to add a test.
 * 
 * @author Andy Cullache.
 */
public class ViewTestSetup extends JDialog implements IViewTestSetup {

	private JPanel contentPane;
	private IControllerTestSetup myController;
	private JList<IRecommender> jListAlgorithms;
	private JList<IMetric> jListMetric;
	private JTextField textName;
	private ITest auxTest;
	private boolean edit = false;
	private JComboBox<String> comboBox;


	/**
	 * Default constructor. Create the dialog.
	 */
	public ViewTestSetup() {
		
		
		this.setModal(true);
		this.edit = false;
		setTitle("Test Setup");
		addComponentListener(new ComponentAdapter() {
			@Override
			public void componentShown(ComponentEvent arg0) {
				setEventTypeComboBox();
				myController.setupMetricMapping();
				setMetricsList();
				setAlgorithmsList();
				if(auxTest != null)
					setTestSetup();
			}
		});
		setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		setBounds(100, 100, 471, 394);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		
		JPanel panel = new JPanel();
		
		JPanel panel_1 = new JPanel();
		
		JPanel panel_2 = new JPanel();
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(
			gl_contentPane.createParallelGroup(Alignment.LEADING)
				.addComponent(panel_1, GroupLayout.DEFAULT_SIZE, 452, Short.MAX_VALUE)
				.addComponent(panel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 452, Short.MAX_VALUE)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addComponent(panel_2, GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE)
					.addContainerGap())
		);
		gl_contentPane.setVerticalGroup(
			gl_contentPane.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_contentPane.createSequentialGroup()
					.addContainerGap()
					.addComponent(panel_2, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addComponent(panel_1, GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(panel, GroupLayout.PREFERRED_SIZE, 41, GroupLayout.PREFERRED_SIZE))
		);
		
		comboBox = new JComboBox();
		comboBox.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent arg0) {
				myController.setupMetricMapping();
				setMetricsList();
				setAlgorithmsList();
			}
		});
		
		JLabel lblEventType = new JLabel("Event type :");
		GroupLayout gl_panel_2 = new GroupLayout(panel_2);
		gl_panel_2.setHorizontalGroup(
			gl_panel_2.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panel_2.createSequentialGroup()
					.addContainerGap()
					.addComponent(lblEventType)
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addComponent(comboBox, 0, 153, Short.MAX_VALUE)
					.addGap(213))
		);
		gl_panel_2.setVerticalGroup(
			gl_panel_2.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panel_2.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_panel_2.createParallelGroup(Alignment.BASELINE)
						.addComponent(lblEventType)
						.addComponent(comboBox, GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE))
					.addGap(10))
		);
		panel_2.setLayout(gl_panel_2);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setViewportBorder(new TitledBorder(null, "Algorithms", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		
		JScrollPane scrollPane_1 = new JScrollPane();
		scrollPane_1.setViewportBorder(new TitledBorder(null, "Metrics", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		GroupLayout gl_panel_1 = new GroupLayout(panel_1);
		gl_panel_1.setHorizontalGroup(
			gl_panel_1.createParallelGroup(Alignment.LEADING)
				.addGroup(Alignment.TRAILING, gl_panel_1.createSequentialGroup()
					.addContainerGap()
					.addGroup(gl_panel_1.createParallelGroup(Alignment.TRAILING)
						.addComponent(scrollPane_1, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 404, Short.MAX_VALUE)
						.addComponent(scrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 404, Short.MAX_VALUE))
					.addContainerGap())
		);
		gl_panel_1.setVerticalGroup(
			gl_panel_1.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panel_1.createSequentialGroup()
					.addContainerGap()
					.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(scrollPane_1, GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE)
					.addContainerGap())
		);
		
		jListMetric = new JList();
		scrollPane_1.setViewportView(jListMetric);
		
		jListAlgorithms = new JList();
		scrollPane.setViewportView(jListAlgorithms);
		panel_1.setLayout(gl_panel_1);
		
		JButton btnNewButton = new JButton("Cancel");
		btnNewButton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				dispose();
			}
		});
		
		JButton btnOk = new JButton("OK");
		btnOk.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				addTest();
			}
			
		});
		getRootPane().setDefaultButton(btnOk);
		
		JLabel lblAlgorithmName = new JLabel("Test Name :");
		lblAlgorithmName.setPreferredSize(new Dimension(95, 14));
		lblAlgorithmName.setMinimumSize(new Dimension(95, 14));
		lblAlgorithmName.setMaximumSize(new Dimension(95, 14));
		
		textName = new JTextField();
		textName.setColumns(10);
		GroupLayout gl_panel = new GroupLayout(panel);
		gl_panel.setHorizontalGroup(
			gl_panel.createParallelGroup(Alignment.TRAILING)
				.addGroup(gl_panel.createSequentialGroup()
					.addContainerGap()
					.addComponent(lblAlgorithmName, GroupLayout.PREFERRED_SIZE, 99, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(textName, GroupLayout.DEFAULT_SIZE, 168, Short.MAX_VALUE)
					.addGap(18)
					.addComponent(btnOk, GroupLayout.PREFERRED_SIZE, 65, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(btnNewButton)
					.addContainerGap())
		);
		gl_panel.setVerticalGroup(
			gl_panel.createParallelGroup(Alignment.LEADING)
				.addGroup(gl_panel.createSequentialGroup()
					.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
					.addGroup(gl_panel.createParallelGroup(Alignment.TRAILING)
						.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE)
							.addComponent(lblAlgorithmName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
							.addComponent(textName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
						.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE)
							.addComponent(btnOk, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
							.addComponent(btnNewButton, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)))
					.addContainerGap())
		);
		panel.setLayout(gl_panel);
		contentPane.setLayout(gl_contentPane);
		this.setLocationRelativeTo(null);
	}

	/**
	 * Add a test based on the parameters selected in this view, this
	 *  method also takes care to edit some test from list of test panel.
	 */
	protected void addTest() {
		if(!edit){
			if(myController.addTest(textName.getText(), metricsSelected(), algorithmsSelected(),comboBox.getSelectedIndex()+1))
				dispose();
		}
		if(edit){
			if(myController.editTest(auxTest, textName.getText(), metricsSelected(), algorithmsSelected(),comboBox.getSelectedIndex()+1)){
				dispose();
				auxTest = null;
			}
		}		
	}

	/**
	 * Sets the controller of this view.
	 * 
	 * @param myController      Test setup controller.
	 */
	@Override
	public void setController(IControllerTestSetup myController) {
		this.myController = myController;		
	}
	
	/**
	 * Establishes the set of metrics project at the hearing to be selected by the user and be associated with a test.
	 */
	private void setMetricsList(){
		try
		{
			DefaultListModel<IMetric> models = new DefaultListModel<IMetric>();
			for (IMetric metric : this.myController.getMetList())
			{
				if (metric.getMetric().getClass().getSuperclass().equals(IPluginErrorMetric.class)
						&& myController.getErrorMetricsTypes().contains("" + (comboBox.getSelectedIndex() + 1)))
				{
					models.addElement(metric);
				}
				if (metric.getMetric().getClass().getSuperclass().equals(IPluginClassificationMetric.class)
						&& myController.getClassificationMetricsTypes().contains("" + (comboBox.getSelectedIndex() + 1)))
				{
					models.addElement(metric);
				}
			}
			this.jListMetric.setModel(models);
		}
		catch (Exception e)
		{
			renderError(Codes.errorLoadMetrics, Messages.errorLoadMetrics);
		}
	}
	
	/**
	 * Establishes the set of algorithms project at the hearing to be selected by the user and be associated with a test.
	 */
	private void setAlgorithmsList(){
		DefaultListModel<IRecommender> models = new DefaultListModel<IRecommender>();		
		for(IRecommender alg : this.myController.getAlgList()){
			if(this.comboBox.getSelectedIndex()==alg.getEventTypeRecommended().getSelectedTag().getID())
				models.addElement(alg);
		}
		this.jListAlgorithms.setModel(models);
	}
	
	/**
	 * Added to the list a JCombobox of all different types of events present in the database.
	 */
	private void setEventTypeComboBox(){
		for(String type : myController.getEventTypes()){
			this.comboBox.addItem(type);
		}
		this.comboBox.setSelectedIndex(auxTest.getEventType()-1);
	}
	
	/**
	 * Get list of selected metrics from the list.
	 * 
	 * @return      Metrics list selected.
	 */
	private List<IMetric> metricsSelected(){
		return this.jListMetric.getSelectedValuesList();
	}
	
	/**
	 * Get list of selected algorithms from the list.
	 * 
	 * @return      Algorithms list selected.
	 */
	private List<IRecommender> algorithmsSelected(){
		return this.jListAlgorithms.getSelectedValuesList();
	}

	/**
	 * Method used to display error messages with the respective code.
	 * 
	 * @param code      Error code.
	 * @param message      Message code.
	 */
	public void renderError(int code, String message) {
		javax.swing.JOptionPane.showMessageDialog(this, code + " - " + message, "Error",javax.swing.JOptionPane.ERROR_MESSAGE);			
	}

	/**
	 * Method used when editing a test, set out in it the selected algorithms and
	 *  metrics that have the test, besides establishing the name of the test.
	 */
	@Override
	public void setTestSetup() {
		int[] indexAlg = new int[auxTest.getAlgorithms().size()];
		int i=0;
		for(IRecommender recSet : auxTest.getAlgorithms()){
			this.jListAlgorithms.setSelectedValue(recSet, true);
			indexAlg[i] = this.jListAlgorithms.getSelectedIndex();
			i++;
		}
		this.jListAlgorithms.setSelectedIndices(indexAlg);
		int[] indexMet = new int[auxTest.getMetrics().size()];
		int j=0;
		for(IMetric metSet : auxTest.getMetrics()){
			this.jListMetric.setSelectedValue(metSet, false);
			indexMet[j] = this.jListMetric.getSelectedIndex();
			j++;
		}
		this.jListMetric.setSelectedIndices(indexMet);
		this.textName.setText(auxTest.getName());
	}

	
	/**
	 * Method is used when editing a test for this parameter that is delivered as object instance ITest.
	 * 
	 * @param test      Test to edit.
	 */
	@Override
	public void setTest(ITest test) {
		this.auxTest = test;
		this.edit = true;
	}


	
	/**
	 * Show this dialog.
	 */
	@Override
	public void render() {
		this.setVisible(true);	
	}

	
	
	/**
	 * Close this dialog.
	 */
	public void close() {
		dispose();
	}

}
